/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.Header;
import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.google.web.bindery.autobean.shared.AutoBeanFactory;
import finbudgettable.client.ui.grid.column.GridColumn;
import finbudget.client.ui.table.Record;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GridPropertiesManager {

    interface ColumnProperties {
        String getFieldName();
        void setFieldName(String fieldName);
        Integer getPosition();
        void setPosition(Integer position);
        String getWidth();
        void setWidth(String width);
        Boolean isVisible();
        void setVisible(Boolean visible);
    }

    interface GridProperties {
        Boolean isMultilineStyle();
        void setMultilineStyle(Boolean multilineStyle);
        List<ColumnProperties> getColumns();
        void setColumns(List<ColumnProperties> columns);
    }

    static interface StateFactory extends AutoBeanFactory {
        AutoBean<GridProperties> gridState();
        AutoBean<ColumnProperties> columnState();
    }

    private static StateFactory factory;

    public static StateFactory ensureFactory() {
        if (factory == null) {
            factory = GWT.create(StateFactory.class);
        }
        return factory;
    }

    public static String serializeToJson(CellGrid grid) {
        StateFactory factory = ensureFactory();

        AutoBean<GridProperties> gridProps = factory.gridState();
        gridProps.as().setMultilineStyle(grid.isMultilineStyle());

        List<ColumnProperties> columnProperties = new ArrayList<ColumnProperties>();
        gridProps.as().setColumns(columnProperties);

        int index = 0;
        for (Column<Record, ?> column : grid.getAllColumns()) {
            AutoBean<ColumnProperties> columnState = factory.columnState();
            columnState.as().setFieldName(((GridColumn<?>) column).getFieldName());
            columnState.as().setPosition(index);
            columnState.as().setVisible(grid.isColumnVisible(column));
            columnState.as().setWidth(grid.getColumnWidth(column));
            columnProperties.add(columnState.as());
            index++;
        }

        return AutoBeanCodex.encode(gridProps).getPayload();
    }

    public static GridProperties deserializeFromJson(String json) {
        StateFactory factory = ensureFactory();
        AutoBean<GridProperties> bean = AutoBeanCodex.decode(factory, GridProperties.class, json);
        return bean.as();
    }

    private static boolean getBool(Boolean value, boolean defaultValue) {
        return value != null ? value : defaultValue;
    }

    private static class ColumnBean {
        private final GridColumn<?> column;
        private final Header<?> header;
        private final Header<?> footer;

        private ColumnBean(GridColumn<?> column, Header<?> header, Header<?> footer) {
            this.column = column;
            this.header = header;
            this.footer = footer;
        }

        public GridColumn<?> getColumn() {
            return column;
        }

        public Header<?> getHeader() {
            return header;
        }

        public Header<?> getFooter() {
            return footer;
        }
    }

    public static void restoreGridProperties(CellGrid grid, GridProperties props) {
        grid.setMultilineStyle(getBool(props.isMultilineStyle(), false));

        Map<String, ColumnBean> columns = new HashMap<String, ColumnBean>();

        for (GridColumn<?> column : grid.getAllColumns()) {
            columns.put(column.getFieldName(), new ColumnBean(column, grid.getHeader(column), grid.getFooter(column)));
        }

        while (grid.getAllHeaders().size() > 0) {
            grid.removeColumn(grid.getAllColumns().get(0));
        }

        for (ColumnProperties colProps : props.getColumns()) {
            ColumnBean bean = columns.get(colProps.getFieldName());
            if (bean != null) {
                grid.insertColumn(grid.getColumnCount(), bean.getColumn(), bean.getHeader(), bean.getFooter());
                grid.setColumnWidth(bean.getColumn(), colProps.getWidth());
            }
        }

        for (ColumnProperties colProps : props.getColumns()) {
            GridColumn<?> column = grid.getColumnByFieldName(colProps.getFieldName());
            if (column != null) {
                if (!colProps.isVisible()) {
                    grid.hideColumn(column);
                }
            }
        }
    }
}
